﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Resources;


namespace SerbinAV.Components
{
    public partial class CustomMessageBox : NonFullScreenForm
    {
        private SizeF _myAutoScaleFactor;
        private MessageBeepType beepType = MessageBeepType.Default;

        #region Native Platform Invoke

        [DllImport("coredll.dll")]
        private static extern int MessageBeep(MessageBeepType uType);

        [DllImport("coredll.dll")]
        private static extern int DrawText(IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);

        [DllImport("coredll.dll")]
        private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hobj);

        [DllImport("coredll.dll")]
        private static extern int DeleteObject(IntPtr HGDIOBJ);

        public enum MessageBeepType : uint
        {
            None = 0xFFFFFFFE,
            Simple = 0xFFFFFFFF,            // Simple beep
            Default = 0x00000000,           // MB_OK
            SystemHand = 0x00000010,        // MB_ICONHAND
            SystemQuestion = 0x00000020,    // MB_ICONQUESTION
            SystemExclamation = 0x00000030, // MB_ICONEXCLAMATION
            SystemAsterisk = 0x00000040     // MB_ICONASTERISK
        }

        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;

            public RECT(Rectangle rc)
            {
                this.Left = rc.Left;
                this.Right = rc.Right;
                this.Top = rc.Top;
                this.Bottom = rc.Bottom;
            }
        }

        private static readonly uint DT_LEFT = 0x00000000;
        private static readonly uint DT_TOP = 0x00000000;
        private static readonly uint DT_WORDBREAK = 0x00000010;
        private static readonly uint DT_CALCRECT = 0x00000400;
        private static readonly uint DT_NOPREFIX = 0x00000800;

        #endregion

        private CustomMessageBox()
        {
            InitializeComponent();
            _myAutoScaleFactor = new SizeF(
              this.AutoScaleDimensions.Width / 96F,
              this.AutoScaleDimensions.Height / 96F);
        }


        public static DialogResult Show(Form owner, string message)
        {
            return Show(owner, message, null, null, MessageBoxIcon.None);
        }

        public static DialogResult Show(Form owner, string message, string caption)
        {
            return Show(owner, message, caption, null, MessageBoxIcon.None);
        }

        public static DialogResult Show(Form owner, string message, Dictionary<string, DialogResult> buttons)
        {
            return Show(owner, message, null, buttons, MessageBoxIcon.None);
        }

        public static DialogResult Show(Form owner, string message, string caption, Dictionary<string, DialogResult> buttons, MessageBoxIcon icon)
        {
            CustomMessageBox form = new CustomMessageBox();
            form.Owner = owner;
            form.Text = caption;
            form.messageLabel.Text = message;
            form.ControlBox = (buttons == null || buttons.Count == 0);
            SizeFormToContent(form, !form.ControlBox);
            if (!form.ControlBox)
            {
                form.SuspendLayout();
                int buttonWidth = (form.pnlButtons.Width - (int)(form._myAutoScaleFactor.Width * 2) - (buttons.Count - 1) * form.pnlButtons.Left) / buttons.Count;
                foreach (KeyValuePair<string, DialogResult> kp in buttons)
                {
                    Button button = new Button();
                    button.Text = kp.Key;
                    button.DialogResult = kp.Value;
                    button.Dock = DockStyle.Left;
                    button.Width = buttonWidth;
                    form.pnlButtons.Controls.Add(button);
                    form.pnlButtons.Controls.SetChildIndex(button, 0);

                    Panel seperator = new Panel();
                    seperator.Width = form.pnlButtons.Left;
                    seperator.Dock = DockStyle.Left;
                    form.pnlButtons.Controls.Add(seperator);
                    form.pnlButtons.Controls.SetChildIndex(seperator, 0);
                }

                form.ResumeLayout();
            }

            switch (icon)
            {
                    case MessageBoxIcon.None:
                    {
                        form.pctBoxImage.Visible = false;
                        //form.messageLabel.Left = 1;
                        //form.messageLabel.Width = 55;
                        break;
                    }
                    case MessageBoxIcon.Hand:
                    {
                        Image im = (Image)new ResourceManager("SerbinAV.Components.CustomMessageBox", Assembly.GetExecutingAssembly()).GetObject("error");
                        form.pctBoxImage.Image = im;
                        break;
                    }
            }
            return form.ShowDialog();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (beepType != MessageBeepType.None)
            {
                MessageBeep(beepType);
            }
        }

        private static Size CalcTextSize(CustomMessageBox form)
        {
            RECT bounds = new RECT(form.mainPanel.ClientRectangle);
            RECT boundsText = new RECT(form.messageLabel.ClientRectangle);
            int titleWidth;
            using (Graphics g = form.CreateGraphics())
            {
                IntPtr hdc = IntPtr.Zero;
                IntPtr hFont = IntPtr.Zero;
                try
                {
                    hdc = g.GetHdc();
                    hFont = form.messageLabel.Font.ToHfont();
                    IntPtr oldFont = SelectObject(hdc, hFont);
                    DrawText(hdc, form.messageLabel.Text, form.messageLabel.Text.Length, ref boundsText, DT_LEFT | DT_TOP | DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK);
                    SelectObject(hdc, oldFont);
                    titleWidth = (int)(g.MeasureString(form.Text, form.Font).Width) + SystemInformation.MenuHeight;
                }
                finally
                {
                    if (hFont != IntPtr.Zero)
                    {
                        DeleteObject(hFont);
                    }

                    if (hdc != IntPtr.Zero)
                    {
                        g.ReleaseHdc(hdc);
                    }
                }
            }
            if ((bounds.Right - bounds.Left) < titleWidth)
            {
                //35 - Height Image
                return new Size(titleWidth, boundsText.Bottom - boundsText.Top < 35 ? 35 : boundsText.Bottom - boundsText.Top);
            }
            else
                return new Size(bounds.Right - bounds.Left + (int)(form._myAutoScaleFactor.Width * 4), boundsText.Bottom - boundsText.Top < 35 ? 35 : boundsText.Bottom - boundsText.Top);

            //return new Size(titleWidth, boundsText.Bottom - boundsText.Top < 35 ? 35 : boundsText.Bottom - boundsText.Top);
        }

        private static void SizeFormToContent(CustomMessageBox form, bool hasButtons)
        {
            form.pnlButtons.Visible = hasButtons;
            form.Width = Screen.PrimaryScreen.WorkingArea.Width / 4 * 3;
            Size textSize = CalcTextSize(form);
            int border = 2*form.mainPanel.Left;
            int width = textSize.Width + border > Screen.PrimaryScreen.Bounds.Width
                            ? Screen.PrimaryScreen.Bounds.Width - border
                            : textSize.Width;
                
//                2 * form.mainPanel.Left + textSize.Width;
            int height = 2 * form.mainPanel.Top + textSize.Height;
            if (hasButtons)
                height += form.mainPanel.Top + form.pnlButtons.Height;
            form.Size = new Size(width, height);
            form.mainPanel.Height = textSize.Height;
            //form.pctBoxImage.Top = (form.mainPanel.Height - form.pctBoxImage.Height) /2;
        }
    }
}
